
#include <BFont>
#include <BPainter>
#include <BMouseEvent>
#include <BKeyEvent>
#include <BScrollBar>

#include "IAlignment.h"
#include "ITabBoard.h"
#include "member_BTabWidget.h"
#include "member_BObject.h"

using namespace BWE;

ITabBoard::ITabBoard(BTabWidget* tabWidget) : BScrollArea(tabWidget)
{
	this->setVisible(false);
	this->items = items;

	boss = tabWidget;
	itemSpace = 3;
	dirty = true;
	hoveredIndex = -1;
	pressedIndex = -1;
}
ITabBoard::~ITabBoard()
{

}

void ITabBoard::freshItemRects()
{
	const BFont* font = this->font();
	if (!font)
		return;

	Form tabForm = tab_member(boss)->tabForm;
	if (tabForm == Form_None)
	{
		for (int i = 0; i < items.size(); i++)
		{
			TabItem& item = items[i];
			if (item.icon)
			{
				tabForm = Form_IconText;
				break;
			}
		}
	}
	Align tabAlign = tab_member(boss)->tabAlign;
	int tabSpacing = tab_member(boss)->tabSpacing;
	BSize realIconSize;
	if (tabForm != Form_TextOnly && tabForm != Form_None)
	{
		realIconSize = iconSize;
		if (font)
		{
			if (realIconSize.width() < 1)
				realIconSize.width() = font->size();
			if (realIconSize.height() < 1)
				realIconSize.height() = font->size();
		}
	}

	int cx = this->centerRect().x();
	int cy = this->centerRect().y();
	int cw = this->centerRect().width();
	int ch = this->centerRect().height();

	contentSize.reset();
	int rowHeight = bMax(realIconSize.height(), font->size());

	int posY = cy;
	for (int i = 0; i < items.size(); i++)
	{
		TabItem& item = items[i];
		if (item.dirty)
		{
			item.freshSize(font);
		}

		item.rect.set(cx, posY, cw, rowHeight);

		item.ia_align = tabAlign;
		item.ia_form = tabForm;
		item.ia_spacing = tabSpacing;
		item.adjust(item.rect);

		posY += rowHeight + itemSpace;
		contentSize.width() = bMax(contentSize.width(), item.ia_hintSize.width());
		contentSize.height() += rowHeight + itemSpace;
	}

	if (items.size())
	{
		contentSize.height() -= itemSpace;
	}

	int top = boss->perch(Part_Top);
	if (contentSize.width() < top)
		contentSize.width() = top;
	if (contentSize.height() < top)
		contentSize.height() = top;

	this->verticalScrollBar()->setStep(rowHeight);

}

BSize ITabBoard::sizeHint() const
{
	if (dirty)
	{
		((ITabBoard*)this)->freshItemRects();
		dirty = false;
	}
	BSize hsize = this->preferSize(contentSize);
	return hsize;
}

void ITabBoard::scrollArea()
{
	showBegin = -1;
	showEnd = -1;
	BRect crect = this->centerRect();
	BPoint offset = this->area().pos();
	for (int i = 0; i < items.size(); i++)
	{
		TabItem& item = items[i];
		BRect rect = item.rect + offset;
		if (rect.bottom() > crect.top())
		{
			showBegin = i;
			showEnd = i;
			break;
		}
	}
	if (showBegin >= 0)
	{
		while (showEnd < items.size())
		{
			TabItem& item = items[showEnd];
			BRect rect = item.rect + offset;
			if (rect.top() > crect.bottom())
				break;
			showEnd++;
		}
	}
	this->fresh();
	BScrollArea::scrollArea();
}

void ITabBoard::resizeEvent(const BEvent& event)
{
	BScrollArea::resizeEvent(event);
	dirty = true;
}

void ITabBoard::styleEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	const BStyle* style = this->realStyle();
	dirty = true;
}
void ITabBoard::freshEvent(const BEvent& event)
{
	BScrollArea::styleEvent(event);
	if (dirty)
	{
		dirty = false;
		freshItemRects();
		BRect area = this->area();
		area.setSize(contentSize);
		this->setArea(area);
	}
}
void ITabBoard::paintEvent(const BEvent& event)
{
	BWidget::paintEvent(event);

	int width = this->width();
	int height = this->height();
	BPoint offset = this->area().pos();

	BPainter painter(this);

	for (int i = showBegin; i < showEnd; i++)
	{
		TabItem& item = items[i];
		BRect rect = item.rect + offset;
		BRect iconRect = item.ia_imageRect + offset;
		BRect textRect = item.ia_textRect + offset;

		StyleRole textColorRole = Color_Text;
		State state = State_Normal;
		if (hoveredIndex == i)
		{
			state = State_Hovered;
			textColorRole = Color_Text_Hovered;
			if(painter.setColor(Color_Item_Hovered))
				painter.fillRect(rect);
		}
		else
		{
			if(painter.setColor(Color_Item))
				painter.fillRect(rect);
		}
		if (painter.setColor(textColorRole))
		{
			if (item.t_title.size())
				painter.drawText(textRect, item.t_title);
			else
				painter.drawText(textRect, item.widget->title());
		}
		if (item.icon)
		{
			BImage* image = item.icon->image(state);
			painter.drawImage(item.ia_imageRect, image, true);
		}
	}
}

void ITabBoard::keyDownEvent(const BKeyEvent& keyEvent)
{
	if (keyEvent.key() == Key_Enter)
	{
		boss->setCurrentIndex(hoveredIndex);
		this->hide();
		return;
	}

	int index = hoveredIndex;
	if (keyEvent.key() == Key_Up)
	{
		index--;
		if (index < 0)
			index = 0;
	}
	if (keyEvent.key() == Key_Down)
	{
		index++;
		if (index >= items.size())
			index = items.size() - 1;
	}
	if (hoveredIndex != index)
	{
		hoveredIndex = index;
		fresh();
	}
}

void ITabBoard::mouseEnterEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex != -1)
	{
		hoveredIndex = -1;
		this->fresh();
	}
}
void ITabBoard::mouseLeaveEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex != -1)
	{
		hoveredIndex = -1;
		this->fresh();
	}
}

void ITabBoard::mouseClickEvent(const BMouseEvent& mouseEvent)
{
	if (hoveredIndex >= 0)
	{
		boss->setCurrentIndex(hoveredIndex);
		BWidget* widget = items[hoveredIndex].widget;
		tab_member(boss)->items.raise(widget);
		tab_member(boss)->dirty = true;
		boss->setCurrentWidget(widget);
		object_member(boss)->emit(Signal_TabClicked, widget);
	}
	arrow->setChecked(!arrow->checked());
}
void ITabBoard::mouseMoveEvent(const BMouseEvent& mouseEvent)
{
	const BPoint& pos = mouseEvent.pos();
	BPoint offset = this->area().pos();
	for (int i = showBegin; i < showEnd; i++)
	{
		TabItem& item = items[i];
		BRect rect = item.rect + offset;
		if (rect.contain(pos))
		{
			if (hoveredIndex != i)
			{
				hoveredIndex = i;
				object_member(boss)->emit(Signal_ItemHovered, hoveredIndex);
				fresh();
			}
			break;
		}
	}
}
